tree grammar JKlasyTypesInit;

options {
	tokenVocab=JKlasy;
	ASTLabelType=Tree;
}

@header {
package compiler.typesinit;
import compiler.common.*;
}

@members {
    private Environment env;
        
    public Environment getEnvironment() {
        return this.env;
    }
}

program returns[Environment env_ret]
	@init { env = new Environment(); }
	: ^(PROGRAM 
		main_part
		  (cd=class_definition 
			{
				try {
					// adds new type to environment
					this.env.addType(cd);
					// adds array of the previous type
					this.env.addType(cd.makeArrayType());
				} catch(Exception e) {
					this.env.addError(e.getMessage());
				}
			} 
		  )*
		)
		{env_ret = this.env;}
	;

main_part
	: ^(MAINPART variable_declaration* statements)
	;
	
class_definition returns [TypeTC type]
	: ^(CLASSDEFINITION ID
		{ type = new TypeTC($ID.text); } 
		(m=operation_descriptor 
			{   
				// for each method in class add it to type description          	    
				try { 
            		type.addMethod(m);
            	} catch(Exception e) {
            	    this.env.addError(e.getMessage());
            	} 
			} 
		)*
	    fields_declaration operation_algorithm*)
	    {
	    	// add default constructor if it was omited in class definition
	    	type.makeDefaultConstructor();
	    }
	;
	
fields_declaration:
  variable_declaration*
  ;	
	
variable_declaration
	: ^(VARIABLEDECLARATION (declaration_type ID)+ )
		
	;

declaration_type
	: ^(DECLARATIONTYPE simple_type (^(ARRAY OF INTNUMBER))?)
	;

parameter_type returns[String type]
	: ^(PARAMETERTYPE 
		s=simple_type
		{ type = s; }
		(^(ARRAY OF)  {type = "array of " + type;}  )?
	  ) 
	;
	
simple_type returns[String type]
	: INTT	  { type = "integer";}
	| BOOLT	  { type = "boolean"; }
	| STRINGT { type = "string"; }
	| REALT   { type = "real"; }
	| CHART	  { type = "char"; }
	| ID      { type = $ID.text; }
	;
	
return_type returns[String type]
	: ^(RESULT pt=parameter_type?) { type = pt; } 
	;

modifier returns[boolean mod]
	: PRIVATE {$mod = false;}
	| PUBLIC  {$mod = true;}
	;
	
designator returns[boolean operator]
	: ID {$operator = false;}
	| relational_operator {$operator = true;}
	| additive_operator {$operator = true;}
	| multiplicative_operator {$operator = true;}
	;
	
operation_descriptor returns[Method method]
	: ^(OPERATIONDESCRIPTOR {mod=false;} (mod=modifier)?  
		b=designator 
		{ 
			// make new method with given name
			method = new Method($designator.text);
			method.setModifier(mod);
			method.setOperator(b.operator);
		} 
		(p=parameter_type { method.addArgType(p); } )* 		
    	rt=return_type { method.setRetType(rt); }
	  )
	;


operation_algorithm
	: ^(OPERATIONALGORITHM designator ^(ARGUMENTS ((ID+)?)) 
	  	  ^(VARIABLES variable_declaration*) statements (^(RETURN expression))?)
	;

statements
	: ^(STATEMENTS statement*)
	;

statement
    : assign_statement
	| if_statement 
	| while_statement
	| input_statement
	| output_statement
	| call_statement
	;

if_statement 
	: ^(IFSTATEMENT expression conditional_option conditional_option?)
	;
	
conditional_option
	: statement
	| statements
	;
	
assign_statement
	: ^(ASSIGNSTATEMENT extended_id (INDEX expression)? expression)  	
	;
	
call_statement
	: ^(CALLSTATEMENT call)
	;

call
	: ^(CALL extended_id expression*)
	;
	
while_statement 
	: ^(WHILESTATEMENT expression statements)
	;

extended_id
	: ^(EXTENDEDID (ID)+)
	;
  
input_statement
	: ^(INPUTSTATEMENT extended_id+)	
	;
			
output_statement
	: ^(OUTPUTSTATEMENT expression+)
	;
	
expression
	: ^(EXPRESSION expr)
	;

expr
	: ^(EQUAL expr expr)
	| ^(NOTEQ expr expr)
	| ^(GR expr expr)
	| ^(GREQ expr expr)
	| ^(LEQ expr expr)
	| ^(LS expr expr)
	| ^(AND expr expr)
	| ^(OR expr expr)
	| ^(PLUS expr expr)
	| ^(MINUS expr expr)
	| ^(DIV expr expr)
	| ^(MOD expr expr)
	| ^(MULT expr expr)
	| INTNUMBER
	| REALNUMBER
	| TRUE
	| FALSE
	| STRING
	| CHAR
	| NULL
	| ^(VAREXPR extended_id (^(INDEX expression))? )
	| ^(NOT expr)
	| ^(CAST expr simple_type)
	| call
	;
	
boolean_operator
	: AND
	| OR
	;
	
relational_operator
	: EQUAL
	| NOTEQ
  	| GR 
  	| GREQ
  	| LS 
  	| LEQ
	;

additive_operator
	: PLUS
	| MINUS
	;

multiplicative_operator
	: DIV 
	| MOD
	| MULT
	;	

operator
	: relational_operator
	| additive_operator
	| multiplicative_operator
	| boolean_operator
	;